#pragma once
#include "Genome_Index_Table.h"
#include "AlignmentsQ.h"
#include "ColorSpaceRead.h"
#include "ShortReadUtil.h"

/*
 * This class has base class CGenome_Index_Table and add query function
 */

class CGenome_Index_TableQ : public CGenome_Index_Table
{
public:
    CGenome_Index_TableQ(void);
    ~CGenome_Index_TableQ(void);
    bool getSeqFromFasta(const char* genomeListfileName, string refFormat = "");
    bool getSeqFromDS(CGenomeNTdata* pgenomeNT);
    bool getSeqFromIndex(char* indexFile);

    // Query a read in bases (illumina) for hit and check uiDiff and put the result into the given Queue
    unsigned int queryReadBases(CReadInBits readInBases, CAlignmentsQ& alignmentsQ, bool bClearQ, bool bForward) const;
    // Query a read in colors (SOLiD) for hit and check uiDiff and put the result into the given Queue
    unsigned int queryReadColors(CReadInBits readInColors, CAlignmentsQ& alignmentsQ, bool bClearQ, bool bForward) const;
    // Given alignments in alignmentsQ, check reads can be also will aligned in the extended position
    unsigned int extendAlignment(CAlignmentsQ& alignmentsQ, CReadInBits readInBases) const;
    bool bExcludeAmbiguous; // If ambiguous reads are exclude, queries can be accelerated.
protected:
    // Query a read for hit and return the hit index range as pair.
    // (Input is pure base or pure color read's substring)
    pair<CIndex_Type*, CIndex_Type*> queryKmer(CReadInBits window, unsigned int shift) const;
private:
    int initialization(void);
    unsigned int getSeedKeyUpperBound(CReadInBits window, unsigned int shift) const;
};

bool testGenome_Index_TableQ(CGenome_Index_TableQ* table);

// Special functor used for lower_bound()
class CcompareFunctor4LowerBound
{
public:
    const CGenome_Index_Table* pGenomeIndexTable;
    CcompareFunctor4LowerBound(const CGenome_Index_Table* pGenomeIndexTable) {
        this->pGenomeIndexTable = pGenomeIndexTable;
    }
    bool operator()(CIndex_Type I1, unsigned int uiQuerySeedKey) {
        unsigned int uiSeedKey;
        if (pGenomeIndexTable->bMapReadInColors) {
            CReadInBits ref = pGenomeIndexTable->pgenomeNTInBits->getSubstringInBits(I1 , pGenomeIndexTable->uiSeedLength + 1);
            CReadInBits refInColors = bases2PureColors(ref);
            uiSeedKey = this->pGenomeIndexTable->getSeedKey(refInColors);
        } else {
            CReadInBits ref = pGenomeIndexTable->pgenomeNTInBits->getSubstringInBits(I1 , pGenomeIndexTable->uiSeedLength);
            uiSeedKey = this->pGenomeIndexTable->getSeedKey(ref);
        }
        return(uiSeedKey < uiQuerySeedKey);
    }
};

// Special functor used for upper_bound()
class CcompareFunctor4UpperBound
{
public:
    const CGenome_Index_Table* pGenomeIndexTable;
    CcompareFunctor4UpperBound(const CGenome_Index_Table* pGenomeIndexTable) {
        this->pGenomeIndexTable = pGenomeIndexTable;
    }
    bool operator()(unsigned int uiQuerySeedKey, CIndex_Type I2) {
        unsigned int uiSeedKey;
        if (pGenomeIndexTable->bMapReadInColors) {
            CReadInBits ref = pGenomeIndexTable->pgenomeNTInBits->getSubstringInBits(I2 , pGenomeIndexTable->uiSeedLength + 1);
            CReadInBits refInColors = bases2PureColors(ref);
            uiSeedKey = this->pGenomeIndexTable->getSeedKey(refInColors);
        } else {
            CReadInBits ref = pGenomeIndexTable->pgenomeNTInBits->getSubstringInBits(I2, pGenomeIndexTable->uiSeedLength);
            uiSeedKey = this->pGenomeIndexTable->getSeedKey(ref);
        }
        return(uiQuerySeedKey < uiSeedKey);
    }
};


